﻿using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using cz.zcu.PreSti.Shapes;
using cz.zcu.PreSti.XNADirectX;
using System.Collections.Generic;

namespace cz.zcu.PreSti.Application
{

    public partial class PresentationWindow : Form
    {
        private Dictionary<string, Symbols> symbols;
        private System.Object lockThis = new System.Object();
        private EventHandler redrawEventHandler;
        Thread presentationRunThread;
        bool readyToStart = false;
        bool windowed = true;

        private XNADirectXPresentation presentation;

        public PresentationWindow(Dictionary<string, Symbols> symbols, bool windowed)
        {
            this.windowed = windowed;
            InitializeComponent();

            Dictionary<string, ISymbols> isymbols = new Dictionary<string, ISymbols>();
            foreach (KeyValuePair<string, Symbols> keyval in symbols)
                isymbols.Add(keyval.Key, keyval.Value);

            // to switch debug/delay logging ON/OFF alter the last parameter
            presentation = new XNADirectXPresentation(isymbols, this, this.Width, this.Height, windowed, false);

            ThreadStart presentationRunDelegate = new ThreadStart(presentation.run);
            presentationRunThread = new Thread(presentationRunDelegate);
            this.symbols = symbols;
            redrawEventHandler = new EventHandler(redraw);
            presentation.Redraw += redrawEventHandler;
            presentation.Terminated += terminated;
        }

        private void redraw(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized) return;
            presentation.draw();  
        }

        private void terminated(object sender, EventArgs e)
        {
            displayTimeTimer.Stop();
            loadingTimer.Stop();
            presentation.GraphicsDevice.Reset();
            if (presentation.HasError) MessageBox.Show(presentation.LastError, "Error in the test scenario", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }

        private void PresentationForm_Shown(object sender, EventArgs e)
        {
            Thread t = new Thread(StartPresentation);
            t.Start();
            loadingTimer.Start();
            if (!windowed) Cursor.Hide();
        }

        private void StartPresentation()
        {
            presentation.initComponents();
            SetControlPropertyValue(loadingToolStripProgressBar.ProgressBar, "Maximum", presentation.SymbolsCount);

            if (!presentation.HasError) readyToStart = true;
            presentation.setPresentationHighPrio(true);
        }

        private void displayTimeTimer_Tick(object sender, EventArgs e)
        {
            TimeToolStripStatusLabel.Text = DateTime.Now.Subtract(presentation.StartTime).ToString();
        }

        private void PresentationForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            presentation.Redraw -= redrawEventHandler;
            presentation.terminate();
            displayTimeTimer.Stop();
        }

        private void loadingTimer_Tick(object sender, EventArgs e)
        {
            if (presentation.IsLoading)
            {
                loadingToolStripProgressBar.Value = presentation.LoadedSymbols;
            }
            else
            {
                loadingTimer.Stop();
                loadingToolStripProgressBar.Visible = false;
                loadingToolStripStatusLabel.Visible = false;
            }
        }

        delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
        private void SetControlPropertyValue(Control oControl, string propName, object propValue)
        {
            if (oControl.InvokeRequired)
            {
                SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
                oControl.Invoke(d, new object[] { oControl, propName, propValue });
            }
            else
            {
                Type t = oControl.GetType();
                PropertyInfo[] props = t.GetProperties();
                foreach (PropertyInfo p in props)
                {
                    if (p.Name.ToUpper() == propName.ToUpper())
                    {
                        p.SetValue(oControl, propValue, null);
                    }
                }
            }
        }

        private void PresentationWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape) this.Close();
            if (e.KeyCode == Keys.Space && readyToStart)
            {
                readyToStart = false;
                if (windowed) displayTimeTimer.Start();
                presentationRunThread.Start();
                spaceLabel.Visible = false;
            }
        }

        private void PresentationWindow_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (!windowed) Cursor.Show();
            presentation.setPresentationHighPrio(false);
        }
    }
}
